package cn.xdf.docscan

import android.content.Context
import android.util.Log
import dalvik.system.DexClassLoader

object ProtoDetectorLoader {
    private const val TAG = "ProtoDetectorLoader"

    data class ParsedDetection(
        val corners: List<Pair<Float, Float>>,
        val statusC: Int?,
        val statusD: Int?
    )

    private var detectorParser: ((ByteArray) -> Any)? = null

    fun init(context: Context) {
        try {
            if (detectorParser != null) return
            val codeCache = context.codeCacheDir
            val dex1 = context.assets.open("docscanui_classes.dex").use { it.readBytes() }
            val dex2 = context.assets.open("docscanui_classes2.dex").use { it.readBytes() }
            val dex1Path = java.io.File(codeCache, "docscanui_classes.dex").apply { writeBytes(dex1) }.absolutePath
            val dex2Path = java.io.File(codeCache, "docscanui_classes2.dex").apply { writeBytes(dex2) }.absolutePath
            val loader = DexClassLoader(
                "$dex1Path:$dex2Path",
                codeCache.absolutePath,
                null,
                context.classLoader
            )
            // 目标类：m38.wub (detections proto)，解析器：m38.tph（GeneratedMessageLite parser）
            val parserHolderClass = loader.loadClass("m38.wub")
            // wub.a 是默认实例(static field)，在该实例上调用 a(7, null) 获取 parser
            val defaultInstance = parserHolderClass.getDeclaredField("a").apply { isAccessible = true }.get(null)
            val generatedMethod = defaultInstance.javaClass.getMethod("a", Int::class.javaPrimitiveType, Any::class.java)
            val PARSE_FROM = 7 // 参照 m38/lsa.java: (tph) wub.a.a(7, null)
            val tphObj = generatedMethod.invoke(defaultInstance, PARSE_FROM, null)
            val tphClass = tphObj.javaClass
            val parseMethod = tphClass.getMethod("d", ByteArray::class.java)
            detectorParser = { bytes ->
                // 返回 wubObj 以便后续多种解析
                parseMethod.invoke(tphObj, bytes)
            }
            Log.d(TAG, "Proto parser loaded")
        } catch (e: Exception) {
            Log.e(TAG, "Failed loading proto parser", e)
        }
    }

    fun parseCorners(bytes: ByteArray): List<Pair<Float, Float>>? {
        return try {
            val wubObj = detectorParser?.invoke(bytes) ?: return null
            val wubClass = wubObj.javaClass
            val detectionsList = wubClass.getDeclaredField("b").apply { isAccessible = true }.get(wubObj) as java.util.List<*>
            if (detectionsList.isEmpty()) return emptyList()
            val wuc = detectionsList[0] ?: return emptyList()
            val wucClass = wuc.javaClass
            val cornersList = wucClass.getDeclaredField("b").apply { isAccessible = true }.get(wuc) as java.util.List<*>
            val corners = mutableListOf<Pair<Float, Float>>()
            for (item in cornersList) {
                val itemClass = item!!.javaClass
                val x = itemClass.getDeclaredField("b").apply { isAccessible = true }.getFloat(item)
                val y = itemClass.getDeclaredField("c").apply { isAccessible = true }.getFloat(item)
                corners.add(x to y)
            }
            corners
        } catch (e: Exception) {
            Log.e(TAG, "parse failed", e)
            null
        }
    }

    fun parseDetections(bytes: ByteArray): List<ParsedDetection>? {
        return try {
            val wubObj = detectorParser?.invoke(bytes) ?: return null
            val detections = mutableListOf<ParsedDetection>()
            val wubClass = wubObj.javaClass
            val detectionsList = wubClass.getDeclaredField("b").apply { isAccessible = true }.get(wubObj) as java.util.List<*>
            for (wuc in detectionsList) {
                if (wuc == null) continue
                val wucClass = wuc.javaClass
                val cornersList = wucClass.getDeclaredField("b").apply { isAccessible = true }.get(wuc) as java.util.List<*>
                val corners = mutableListOf<Pair<Float, Float>>()
                for (item in cornersList) {
                    val itemClass = item!!.javaClass
                    val x = itemClass.getDeclaredField("b").apply { isAccessible = true }.getFloat(item)
                    val y = itemClass.getDeclaredField("c").apply { isAccessible = true }.getFloat(item)
                    corners.add(x to y)
                }
                // 读取状态字段（可能为枚举或int）
                val statusC = try { wucClass.getDeclaredField("c").apply { isAccessible = true }.get(wuc) as? Int } catch (e: Exception) { null }
                val statusD = try { wucClass.getDeclaredField("d").apply { isAccessible = true }.getInt(wuc) } catch (e: Exception) { null }
                detections.add(ParsedDetection(corners, statusC, statusD))
            }
            detections
        } catch (e: Exception) {
            Log.e(TAG, "parseDetections failed", e)
            null
        }
    }
}


